package com.zf.zffencheng.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zf.zffencheng.constant.AccountConstant;
import com.zf.zffencheng.dao.AdminDao;
import com.zf.zffencheng.exception.Error_;
import com.zf.zffencheng.exception.ResultException;
import com.zf.zffencheng.model.dto.AdminLoginDTO;
import com.zf.zffencheng.model.dto.ResetPwdDTO;
import com.zf.zffencheng.model.dto.UpdatePwdDTO;
import com.zf.zffencheng.model.pojo.MasterSubsidiaryAdmin;
import com.zf.zffencheng.model.pojo.TAdmin;
import com.zf.zffencheng.model.vo.AdminLoginInfoVo;
import com.zf.zffencheng.service.*;
import com.zf.zffencheng.util.HashUtils;
import com.zf.zffencheng.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.mindrot.jbcrypt.BCrypt;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

/**
 * ClassName: AdminServiceImpl <br/>
 * Description:  <br/>
 * date: 2021/5/8 16:25<br/>
 *
 * @author william <br/>
 */
@Service
@Slf4j
public class AdminServiceImpl extends ServiceImpl<AdminDao, TAdmin> implements AdminService {

    private final RedissonClient redissonClient;
    private final SmsService smsService;

    @Autowired
    private MasterSubsidiaryAdminService masterSubsidiaryAdminService;

    @Autowired
    public AdminServiceImpl(RedissonClient redissonClient, SmsService smsService) {
        this.redissonClient = redissonClient;
        this.smsService = smsService;
    }

    /**
     * 登录
     *
     * @param adminLoginDTO
     * @return
     */
    @Override
    public AdminLoginInfoVo login(AdminLoginDTO adminLoginDTO) {
        String loginNo = adminLoginDTO.getMobile();
        TAdmin tAdmin = byAdminNo(loginNo);
        if(tAdmin == null){
            //账号不存在
            throw new ResultException(Error_.LOGIN_ACCOUNT_NOT_FIND);
        }

        String password = "password";
        String mobile = "mobile";

        //账号登录
        if(password.equals(adminLoginDTO.getType())){
            //密码校验
            String saltValue = tAdmin.getSaltValue();
            String md5 = HashUtils.getMd5((adminLoginDTO.getPassword() + saltValue).getBytes());
            if(!md5.equals(tAdmin.getPassword())){
                throw new ResultException(Error_.USER_PASSWORD_ERROR);
            }
        }
        //手机号登录
        else if(mobile.equals(adminLoginDTO.getType())){
            //短信校验
            smsService.verifyCode(adminLoginDTO.getMobile(), adminLoginDTO.getCode());
        }else{
            //登录方式不正确
            throw new ResultException(Error_.LOGIN_ACCOUNT_NOT_FIND);
        }
        String id = tAdmin.getId().toString();
        //生成签名
        String jwt = JwtUtil.createJwt(id, String.format(JwtUtil.admin_subject, tAdmin.getId(), tAdmin.getAdminType()), 0);

        Integer  accountId = null;
        Integer adminType = tAdmin.getAdminType();
        switch (adminType){
            case 1:
                //平台
                accountId = AccountConstant.PLATFORM_ID;
                break;
            case 2:
                //寺院
                accountId = tAdmin.getStoreID();
                break;
            case 4:
                MasterSubsidiaryAdmin masterSubsidiaryAdmin =  masterSubsidiaryAdminService.bySubAdminId(tAdmin.getId());
                //资方
                if(masterSubsidiaryAdmin == null){
                    throw new ResultException(Error_.ACCOUNT_NOT_FUND);
                }
                accountId = masterSubsidiaryAdmin.getInvestorId();
                break;
            default:
                throw new ResultException(Error_.ACCOUNT_NOT_FUND);
        }

        AdminLoginInfoVo adminLoginInfoVo = new AdminLoginInfoVo(tAdmin.getId(), jwt, tAdmin.getAdminType());
        //创建redis添加缓存
        RBucket<AdminLoginInfoVo> bucket = redissonClient.getBucket(LOGIN_TOKEN_BUCKET.concat(":").concat(jwt), new JsonJacksonCodec());
        bucket.set(adminLoginInfoVo, LOGIN_EXPIRE, TimeUnit.SECONDS);
        return adminLoginInfoVo;
    }

    /**
     * 查询用户
     * @param mobile
     * @return
     */
    @Override
    public TAdmin byAdminNo(String mobile){
        QueryWrapper<TAdmin> queryWrapper = new QueryWrapper<>();
        QueryWrapper<TAdmin> adminNo = queryWrapper.eq("adminNo", mobile);
        return getOne(adminNo, false);
    }

    /**
     * 重置密码
     *
     * @param resetPwdDTO
     */
    @Override
    public void resetPwd(ResetPwdDTO resetPwdDTO) throws Exception {
        //管理员查询
        String mobile = resetPwdDTO.getMobile();
        TAdmin tAdmin = byAdminNo(mobile);
        if(tAdmin == null){
            throw new ResultException(Error_.ADMIN_NOT_EXIST);
        }
        String code = resetPwdDTO.getCode();
        // 短消息校验
        smsService.send(mobile, code);
        //盐值
        String saltValue = tAdmin.getSaltValue();
        //md5密码
        String md5 = HashUtils.getMd5((resetPwdDTO.getPassword() + saltValue).getBytes());
        tAdmin.setPasswords(resetPwdDTO.getPassword());
        tAdmin.setPassword(md5);
        //修改参数
        updateById(tAdmin);
    }

    /**
     * 重置支付密码
     *
     * @param updatePwdDTO
     */
    @Override
    public void resetPayPwd(UpdatePwdDTO updatePwdDTO) {

        TAdmin tAdmin = getById(updatePwdDTO.getAdminId());
        //盐值
        String saltValue = tAdmin.getSaltValue();
        String pwd = updatePwdDTO.getPassword()+"_"+saltValue;
        //加密
        String hashed = BCrypt.hashpw(pwd, BCrypt.gensalt());
        log.info("原文：{}, 密文:{}", pwd, hashed);
        tAdmin.setPayPassword(hashed);
        //重置密码
        UpdateWrapper<TAdmin> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("payPassWord", hashed);
        updateWrapper.eq("id", tAdmin.getId());
        update(updateWrapper);
    }

    /**
     * 密码校验
     *
     * @param inputPwd
     * @param sourcePwd
     * @param salt
     */
    @Override
    public void verifyPayPwd(String inputPwd, String sourcePwd, String salt) {
        String pwd = inputPwd+"_"+salt;
        //密码, 加密后的密码
        boolean matches = BCrypt.checkpw(pwd, sourcePwd);
        log.info("原文:{}, 密文:{} , 校验:{}", pwd, sourcePwd, matches);
        //密码校验失败
        if(!matches){
            throw new ResultException(Error_.PAY_VERIFY_ERROR);
        }

    }


}
